# beyound functions

import sys
import imp
import os.path
import linecache


# file
def trace(f):
    '''Decorator used to trace every line of the source code.'''
    def globaltrace(frame, why, arg):
        if why == "call":
            return localtrace
        return None
    def localtrace(frame, why, arg):
        if why == "line":
            # record the file name and line number of every trace
            filename = frame.f_code.co_filename
            lineno = frame.f_lineno
            bname = os.path.basename(filename)
            print('%s(%s): %s' %(bname, lineno,
                  linecache.getline(filename, lineno)))
        return localtrace
    def _f(*args, **kw):
        sys.settrace(globaltrace)
        result = f(*args, **kw)
        sys.settrace(None)
        return result
    return _f


# module
class importer(object):
    @classmethod
    def takeover():
        sys.meta_path = [ importer() ]

    def __init__(self):
        self._code = ''

    def find_module(self, filename, path=None):
        with open(filename, 'rt') as fd:
            self._code = fd.read()
        return self if self._code else None

    def load_module(self, name):
        module = imp.new_module(name)
        exec(self._code, module.__dict__)
        sys.modules[name] = module
        return module


# class
class Singleton(type):
    def __init__(cls, name, bases, dict):
        super(Singleton, cls).__init__(name, bases, dict)
        cls._instance = None

    def __call__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = super(Singleton, cls).__call__(*args, **kw)
        return cls._instance


# object

def delegate(obj, proxy):
    attrs = [x for x in dir(proxy) if not x.startswith('__')]
    for attr in attrs:
        if not getattr(obj, attr, None):
            setattr(obj, attr, getattr(proxy, attr))
    return obj
